﻿Imports System.Text

Public Class Form1

    Dim gpsGGATime
    Dim gpsGGALatitude
    Dim gpsGGALatitudeNS
    Dim gpsGGALongitude
    Dim gpsGGALongitudeEW
    Dim gpsGGAFixQuality
    Dim gpsGGASatellites
    Dim gpsGGAHorizontalDilution
    Dim gpsGGAAltitude
    Dim gpsGGAAltUnits
    Dim gpsGGAGeoidHeight
    Dim gpsGGASinceLastUpdate
    Dim gpsGGADGPSStationID
    Dim gpsGGAChecksum

    Dim gpsDecLat
    Dim gpsDecLong

    Dim objLock As Object = New Object()

    Public Function nmeaToDecimal(ByVal posData As String, ByVal posType As Integer)
        If posData <> vbNull And IsNumeric(posData) = True Then
            If posType = 0 Then '/// 0 = Latitude
                gpsDecLat = Val(Strings.Left(posData, 2) + (Val(Strings.Right(posData, Len(posData) - 2)) / 60))
                gpsDecLat = Format(gpsDecLat, "000.0000")
                If gpsGGALatitudeNS = "S" Then gpsDecLat = -gpsDecLat
                Return gpsDecLat
            ElseIf posType = 1 Then '/// 1 = Longitude
                gpsDecLong = Val(Strings.Left(posData, 3) + (Val(Strings.Right(posData, Len(posData) - 3)) / 60))
                gpsDecLong = Format(gpsDecLong, "000.0000")
                If gpsGGALongitudeEW = "W" Then gpsDecLong = -gpsDecLong
                Return gpsDecLong
            Else
                Exit Function
            End If
        End If
        '/// Usage:
        '/// myLongitude = nmeaToDecimal(gpsGGALongitude, 1)
        '/// myLatitude = nmeaToDecimal(gpsGGALatitude, 0)
    End Function

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        initUI()
    End Sub

    Public Sub initUI()
        '/// Clear text boxes to "NO DATA", doesn't require threading, no reading from the serial port.
        Label1.Text = "Time: NO DATA"
        Label2.Text = "Latitude: NO DATA"
        Label3.Text = "LatitudeNS: NO DATA"
        Label4.Text = "Longitude: NO DATA"
        Label5.Text = "LongitudeEW: NO DATA"
        Label6.Text = "Fix Quality: NO DATA"
        Label7.Text = "Sattellites: NO DATA"
    End Sub

    Public Function ParseGPS(ByVal gpsSentence As String)

        Dim gpsNextLine As String
        Dim gpsGGA(16) As String

        gpsNextLine = gpsSentence

        If Strings.Left(gpsNextLine, 6) = "$GPGGA" Then
            gpsGGA = Split(gpsNextLine, ",")
            gpsGGATime = Val(gpsGGA(1))
            gpsGGALatitude = gpsGGA(2)
            gpsGGALatitudeNS = gpsGGA(3)
            gpsGGALongitude = gpsGGA(4)
            gpsGGALongitudeEW = gpsGGA(5)
            gpsGGAFixQuality = gpsGGA(6)
            gpsGGASatellites = gpsGGA(7)
            gpsGGAHorizontalDilution = gpsGGA(8)
            gpsGGAAltitude = gpsGGA(9)
            gpsGGAAltUnits = gpsGGA(10)
            gpsGGAGeoidHeight = gpsGGA(11)
            gpsGGAAltUnits = gpsGGA(12)
            gpsGGASinceLastUpdate = gpsGGA(13)
            gpsGGAChecksum = Strings.Right(gpsGGA(14), 3)
            gpsGGADGPSStationID = Strings.Left(gpsGGA(14), Len(gpsGGA(14)) - 4)
        End If

    End Function

    Public Delegate Sub gpsDelegate()
    Private Sub gpsDataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort.DataReceived
        ParseGPS(SerialPort.ReadLine())
        '/// Switched these two lines because it makes no sense to display before you read, you have old data.
        Label1.Invoke(New gpsDelegate(AddressOf updateTextBox), New Object() {})
        '/// Don't put updateTextBox() here, the Invoke above already does it!
        '/// Serial port access is another thread, and you can't talk directly from thread to thread.
        '/// Instead, to update the UI, you need to use Invoke rather than calling it normally.
    End Sub

    Public Sub updateTextBox()
        If gpsGGATime = vbNullString Then
            initUI()
        Else
            Label1.Text = "Time: " & Format(gpsGGATime, "00:00:00")
            Label2.Text = "Latitude: " & gpsGGALatitude
            Label3.Text = "LatitudeNS: " & gpsGGALatitudeNS
            Label4.Text = "Longitude: " & gpsGGALongitude
            Label5.Text = "LongitudeEW: " & gpsGGALongitudeEW
            Label6.Text = "Fix Quality: " & gpsGGAFixQuality
            Label7.Text = "Sattellites: " & gpsGGASatellites
        End If
    End Sub

    Private Sub ReadDataToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ReadDataToolStripMenuItem.Click
        Try
            SerialPort.Close()
            SerialPort.Open()
        Catch ex As Exception
            MsgBox("Read Error")
        End Try
    End Sub

    Private Sub BaudRateToolStripMenuItem_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BaudRateToolStripMenuItem.Click
        Dim baud As String
        baud = InputBox("Enter Baud Rate")
        If IsNumeric(baud) = True Then
            SerialPort.Close()
            Try
                SerialPort.BaudRate = baud
                BaudRateLabel.Text = baud & " Baud"
                SerialPort.Open()
            Catch ex As Exception
                SerialPort.Close()
                SerialPort.BaudRate = 4800
                BaudRateLabel.Text = "4800 Baud"
                MsgBox("Invalid Baud Rate!")
            End Try
        Else
            MsgBox("Baud Rate Must Be Numeric!")
        End If
    End Sub

    Private Sub SerialPortToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SerialPortToolStripMenuItem.Click
        Dim prt As String
        prt = InputBox("Enter Serial Port Number")
        If IsNumeric(prt) = True Then
            If prt <= 99 Then
                SerialPort.Close()
                SerialPort.PortName = "COM" & prt
                SerialPortLabel.Text = "COM" & prt
                Try
                    SerialPort.Open()
                Catch ex As Exception
                    MsgBox("Port Does Not Exist! Please choose another port!")
                    SerialPort.PortName = "COM1"
                    SerialPortLabel.Text = "COM1"
                End Try

            Else
                MsgBox("Invalid Port Number!")
            End If
        Else
            MsgBox("Port must be a number!")
        End If
    End Sub

    Private Sub AboutToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AboutToolStripMenuItem.Click
        AboutBox1.Show()
    End Sub

    Private Sub ShowMapToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ShowMapToolStripMenuItem.Click
        Form2.Show()
        Form2.WebBrowser1.Navigate("http://maps.google.com/maps?q=" & nmeaToDecimal(gpsGGALatitude, 0) & "%2C" & nmeaToDecimal(gpsGGALongitude, 1))
    End Sub

End Class